home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’96
/
Better AD security
/
Source
/
ExtensionShell.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-06-21
|
15KB
|
659 lines
/* NAME:
ExtensionShell.c
WRITTEN BY:
Dair Grant, dair@kagi.com
DESCRIPTION:
This file contains the main entry point of Extension Shell. It
calls everything else to do the actual work.
NOTES:
We don't lock our code resource down by hand, so we depend on
having the System Heap and Locked attributes set.
RELEASE INFORMATION:
Extension Shell is freeware, and Copyright © 1993-96 Dair Grant.
You may not charge for Extension Shell itself, or redistribute
it as part of a commercial package without my prior permission.
If you use Extension Shell in a commercial Extension, you are
obliged to display some form of indication that your product
uses Extension Shell. This notice must be plainly visible to
users (either in the 'vers' resource, or in some other form of
documentation), and not just those curious enough to use ResEdit.
Shareware and Freeware products can use the code without notice.
___________________________________________________________________________
*/
//=============================================================================
// Include files
//-----------------------------------------------------------------------------
#include <MixedMode.h>
#include <Resources.h>
#include <Gestalt.h>
#include "A4Stuff.h"
#include "SetupA4.h"
#include "ES.h"
#include "ES Address Table.h"
#include "ExtensionShell.h"
#include "InstallCode.h"
#include "UninstallCode.h"
#include "ShowIcon.h"
#include "NotifyMsg.h"
//=============================================================================
// Private function prototypes
//-----------------------------------------------------------------------------
void main(void);
void InitToolbox(void);
void InitParamBlock(void);
void CallESHandler(short theMsg);
OSErr DoInstall(void);
void DoUninstall(void);
void DoErrors(void);
void DoIcons(void);
pascal Boolean IsKeyMouseDown(short keyCode, Boolean checkMouse);
pascal Boolean IsTrapAvailable(short trapWord);
pascal Boolean IsPowerMac(void);
pascal Boolean IsTrapNative(short trapWord);
//=============================================================================
// Global variables
//-----------------------------------------------------------------------------
FakeQD gTheQDGlobals;
ESParamBlock gTheParamBlock;
ESAddressTable *gTheESAddressTable;
//=============================================================================
// main : Entry point to our 'INIT' code resource.
//-----------------------------------------------------------------------------
// Note : We need to set up A4 so that we can access our globals. We
// do this using the standard Metrowerks routines.
//
// We don't lock ourself down in memory, or call DetachResource
// on ourselves. We assume that the 'INIT' resource was compiled
// with the System Heap and Locked attributes set.
//-----------------------------------------------------------------------------
void main(void)
{ long oldA4;
THz oldZone;
// Set up A4 and switch to the System Zone
#ifndef powerc
oldA4 = SetCurrentA4();
#endif
oldZone = GetZone();
SetZone(SystemZone());
// Initialise Extension Shell and the ES Handler
InitToolbox();
InitParamBlock();
CallESHandler(kInitialiseParamBlock);
// Install everything the ES Handler requested
if (DoInstall() != noErr)
{
// If there's a problem, let the handler know
CallESHandler(kHandleError);
// If we're allowed to, try and clean up after ourselves
if (gTheParamBlock.removeInstalledCode)
DoUninstall();
}
// If the ES Handler has registered an error, handle it
if (gTheParamBlock.beepNow || gTheParamBlock.postError)
DoErrors();
// Show any icons which are to be shown
DoIcons();
// Restore the heap zone and A4
SetZone(oldZone);
#ifndef powerc
SetA4(oldA4);
#endif
}
//=============================================================================
// InitToolbox : Initialises the Toolbox.
//-----------------------------------------------------------------------------
// Note : If we initialise all the Toolbox Managers, we will erase the
// screen. This looks ugly - so don't define __InitAllToolbox__
// unless you really don't care.
//-----------------------------------------------------------------------------
void InitToolbox(void)
{
// Initialise the bits of the Toolbox that we need
InitGraf(&gTheQDGlobals.thePort);
#ifdef __InitAllToolbox__
// This fixes the pre-Mac II bug that can happen if we try
// and create a window from within an INIT.
*((void**)DragHook) = nil;
*((void**)DeskHook) = nil;
// Initialise the rest of the Toolbox
InitFonts();
InitWindows();
InitCursor();
InitMenus();
InitDialogs(nil);
TEInit();
#endif
// Flush out any events that may be lurking
FlushEvents(everyEvent, 0);
FlushEvents(everyEvent, 0);
FlushEvents(everyEvent, 0);
}
//=============================================================================
// InitParamBlock : Initialise gTheParamBlock.
//-----------------------------------------------------------------------------
// Note : We want to minimise the work the ES Handler has to do, so
// we initialise the fields to their most 'normal' values.
//-----------------------------------------------------------------------------
void InitParamBlock(void)
{ OSErr myErr;
// Initialise the general values
myErr = Gestalt(gestaltSystemVersion, &gTheParamBlock.systemVersion);
gTheParamBlock.NotificationMsg = NotificationMessage;
gTheParamBlock.IsKeyMouseDown = IsKeyMouseDown;
gTheParamBlock.IsTrapAvailable = IsTrapAvailable;
gTheParamBlock.IsPowerMac = IsPowerMac;
gTheParamBlock.IsTrapNative = IsTrapNative;
// Initialise the Icon related values
gTheParamBlock.numIcons = 0;
gTheParamBlock.animationDelay = 3;
// Initialise the installable code related values
gTheParamBlock.installAddressTable = false;
gTheParamBlock.numCodeResources = 0;
gTheParamBlock.errorIndex = 0;
gTheParamBlock.theErr = noErr;
// Initialise the error handling related values
gTheParamBlock.removeInstalledCode = false;
gTheParamBlock.beepNow = false;
gTheParamBlock.postError = false;
gTheParamBlock.errorStringsID = 0;
gTheParamBlock.errorStringIndex = 0;
}
//=============================================================================
// CallESHandler : Execute the ES Handler CODE resource.
//-----------------------------------------------------------------------------
// Note : This routine can be called several times. We load the CODE
// resource in once, and save it in a static variable. When
// the System closes our resource fork, the code will get
// flushed out (we're not calling DetachResource).
//
// If we can't find the ES Handler, we drop into the Debugger.
//-----------------------------------------------------------------------------
void CallESHandler(short theMsg)
{ static ESHandlerProc theHandler = (ESHandlerProc) nil;
Handle theHnd;
// If we've not already loaded the code, do so, and lock it down
if (theHandler == nil)
{
theHnd = Get1Resource(kESHandlerCodeType, kESHandlerCodeID);
if (theHnd == nil)
DebugStr("\pExtension Shell - couldn't find ES Handler");
else
HLock(theHnd);
theHandler = (ESHandlerProc) StripAddress(*theHnd);
}
// Call the code with the message and the param block
(*theHandler)(theMsg, &gTheParamBlock);
}
//=============================================================================
// DoInstall : Install what the ES Handler wants installed.
//-----------------------------------------------------------------------------
// Note : This routine attempts to install the routines the ES Handler
// has requested. If there is a problem, the appropriate fields
// in gTheParamBlock will be filled in, and an error code
// returned.
//-----------------------------------------------------------------------------
OSErr DoInstall(void)
{ short i;
OSErr theErr = noErr;
// Install the address table, if one has been requested. This has to
// be done first in case installed code is going to be called before
// we're finished (e.g., a trap patch to GetResource).
//
// If the address table is installed correctly, we call the ES
// Handler to give it a chance to initialise any fields it may
// have added. If it sets gTheParamBlock.theErr to anything other
// than noErr, we abort the installation process.
if (gTheParamBlock.installAddressTable)
{
InstallESAddressTable();
CallESHandler(kInitialiseAddrsTable);
if (gTheParamBlock.theErr != noErr)
return(gTheParamBlock.theErr);
}
// Install each resource in turn. If there's a problem, we save the
// error details and break out of the loop.
if (gTheParamBlock.numCodeResources >= 1)
{
for (i = 1; i <= gTheParamBlock.numCodeResources && theErr == noErr; i++)
{
theErr = InstallCode(i);
if (theErr != noErr)
{
gTheParamBlock.errorIndex = i;
gTheParamBlock.theErr = theErr;
}
}
}
// Return any error code
return(gTheParamBlock.theErr);
}
//=============================================================================
// DoUninstall : Try and uninstall anything which has been installed.
//-----------------------------------------------------------------------------
// Note : This routine attempts to remove the routines the ES Handler
// resource tried to install. The error index is assumed to
// indicate which resource could not be installed, and so
// only entries before this index are candidates for removal.
// We make *no* guarantees as to what can be removed. Hopefully,
// most things can, but you never know.
//-----------------------------------------------------------------------------
void DoUninstall(void)
{ short i;
// gTheParamBlock.ErrorIndex contains the index of the item that
// couldn't be installed. We try and uninstall everything before this.
if (gTheParamBlock.errorIndex > 1 && gTheParamBlock.numCodeResources >= 1)
{
for (i = 1; i < gTheParamBlock.errorIndex; i++)
UninstallCode(i);
}
}
//=============================================================================
// DoErrors : Provide some error handling capabilities.
//-----------------------------------------------------------------------------
// Note : This routine is how Extension Shell communicates errors to the
// user. The two functions it offers are to beep, and to post a
// Notification Manager dialog to the user.
//-----------------------------------------------------------------------------
void DoErrors(void)
{
// If we're to beep, do so now
if (gTheParamBlock.beepNow)
SysBeep(30);
// If we're to post a NM message, do so
if (gTheParamBlock.postError)
NotificationMessage(gTheParamBlock.errorStringsID, gTheParamBlock.errorStringIndex);
}
//=============================================================================
// DoIcons : Call PlotINITIcon to display the icons.
//-----------------------------------------------------------------------------
// Note : We pull the values out of gTheParamBlock, and let PlotINITIcon
// do all the work.
//-----------------------------------------------------------------------------
void DoIcons(void)
{ Boolean useIconSuite;
// Call PlotINITIcon to do the work
useIconSuite = IsTrapAvailable(_OpenCPort) && IsTrapAvailable(_IconDispatch);
PlotINITIcon(useIconSuite,
gTheParamBlock.animationDelay,
gTheParamBlock.numIcons,
&gTheParamBlock.theIcons);
}
//=============================================================================
// IsKeyMouseDown : Called by the ES Handler to scan the keyboard.
//-----------------------------------------------------------------------------
// Note : We return true if the key corresponding to KeyCode is pressed,
// and false otherwise.
//
// If checkMouse is true, we also return false if the mouse is not
// pressed, and true if it is.
//-----------------------------------------------------------------------------
pascal Boolean IsKeyMouseDown(short keyCode, Boolean checkMouse)
{ unsigned char theKeys[16];
// First check the keyboard
GetKeys((void *) theKeys);
if ((theKeys[keyCode >> 3] >> (keyCode & 7)) & 1)
return(true);
// Then check the mouse, if we're allowed to
if (checkMouse)
return(Button());
// If we've got this far, nothing is being pressed
return(false);
}
//=============================================================================
// IsTrapAvailable : Determines if a given trap number is implemented.
//-----------------------------------------------------------------------------
pascal Boolean IsTrapAvailable(short trapWord)
{ TrapType trapType;
short numToolboxTraps;
// Check trap word for Toolbox bit
trapType = (trapWord & 0x0800) ? ToolTrap : OSTrap;
// If it's a Toolbox trap...
if (trapType == ToolTrap)
{
// Mask through largest # of traps available
trapWord &= 0x07FF;
// Is _InitGraf at the same address as 0xAA6E?
if (NGetTrapAddress(kInitGrafTrap,ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
numToolboxTraps = 0x0200; // Yes, only this many entries in dispatch table
else
numToolboxTraps = 0x0400; // No, dispatch table is larger
// Trap # bigger than dispatch table? If so it's a bogus trap, so abort
if (trapWord > numToolboxTraps)
return(false);
}
// Return trap address if it's not an unimplemented trap
return(NGetTrapAddress(trapWord, trapType) != NGetTrapAddress(kUnimplementedTrap, ToolTrap));
}
//=============================================================================
// IsPowerMac : Is this a PowerMac?
//-----------------------------------------------------------------------------
pascal Boolean IsPowerMac(void)
{ long result;
OSErr theErr;
theErr = Gestalt(gestaltSysArchitecture, &result);
if (theErr == noErr && result == gestaltPowerPC)
return(true);
else
return(false);
}
//=============================================================================
// IsTrapNative : Is a trap native?
//-----------------------------------------------------------------------------
pascal Boolean IsTrapNative(short trapWord)
{ TrapType trapType;
short *theCode;
// Get the address of the trap code
trapType = (trapWord & 0x0800) ? ToolTrap : OSTrap;
theCode = (short *) NGetTrapAddress(trapWord, trapType);
// If the trap is native, it will start with the Mixed Mode Magic word
return(*theCode == _MixedModeMagic);
}